package cn.antalk.top.normal.service.impl;


import cn.antalk.top.normal.dao.TalkDao;
import cn.antalk.top.normal.entity.*;
import cn.antalk.top.normal.service.TalkService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @Author: WackyBoy
 * @Date: 2021/12/4 19:04
 */
@Service("TalkService")
public class TalkServiceImpl implements TalkService {

    @Autowired
    public TalkDao talkDao;

    @Autowired
    StringRedisTemplate redisTemplate;


    @Override
    // TODO: tag_name seg
    public boolean pushTalk(int user_id, String content) {
        Date create_time = new Date();
        Talk talk = new Talk();
        talk.setUid(user_id);
        talk.setContent(content);
        talk.setCreate_time(create_time);
        return talkDao.pushTalk(talk) == 1;

    }

    @Override
    public List<Talk_User> getTalkByPageAndCount(int page, int count) {
        List<Talk> talkList = talkDao.getTalkByPageAndCount(page, count);
        List<Talk_User> talk_users = new ArrayList<>();
        for(Talk talk : talkList) {
            Talk_User talk_user = new Talk_User();
            int uid = talk.getUid();
            User user = talkDao.getUserByUid(uid);
            if(user == null) continue;
            List<Integer> likeList = getLike2UidByTalkId(talk.getTalk_id());
            talk_user.setLikeUidList(likeList);
            talk_user.setTalk(talk);
            talk_user.setUname(user.getUname());
            talk_user.setAvatar(user.getAvatar());
            talk_users.add(0, talk_user);
        }
        return talk_users;


    }

    @Override
    public List<Integer> getLike2UidByTalkId(Integer talk_id) {
        return talkDao.getLike2UidByTalkId(talk_id);

    }

    // TODO: why need transactional and change the method to redis + schedule task
    @Transactional
    @Override
    public int changeLikeState(int uid, int talk_id) {
        List<Like> hasLike = talkDao.hasLike(uid, talk_id);
        boolean flag = false;
//        AtomicInteger like_total = new AtomicInteger(0);
        int like_total = 0;
        synchronized (TalkServiceImpl.class) {
            if(hasLike.size() != 0) {
                // change talk table
                Talk talk = talkDao.getTalkByTalkId(talk_id);

                like_total = talk.getLike_count() + (hasLike.get(0).getIslike() == 0 ? 1 : -1);
                talkDao.changeTalkLikeCount(talk_id, like_total);
//                like_total.set(talk.getLike_count() + (hasLike.get(0).getIslike() == 0 ? 1 : -1));
                flag = talkDao.changeLikeState(uid, talk_id, 1 - hasLike.get(0).getIslike()) == 1;
            } else {
                flag = talkDao.insertLikeByUidAndTalkId(uid, talk_id) == 1;
                talkDao.changeTalkLikeCount(talk_id, 1);
//                like_total.set(1);
                like_total = 1;
            }
        }

//        return like_total.get();
        return like_total;
    }

    // TODO: getCommentList optimization
    @Override
    public List<CommentForShow> getTalkCommentAllInfoByTalkId(int talkId, Boolean hasCookie) {
        List<Comment> commentList = getTalkCommentByTalkId(talkId);
        List<CommentForShow> commentForShowList = new ArrayList<>();
        for(Comment comment : commentList) {
            CommentForShow commentForShow = new CommentForShow();
            // TODO: search corresponding reply table likeStatus by commentId and currentUserId, user session(have or not), then set likeStatus
            String u_id = redisTemplate.opsForValue().get("u_id");
            if (!StringUtils.isEmpty(u_id) && hasCookie) {
                // user has login
                int uid = Integer.parseInt(u_id);
                ReplyLike replyLike = this.talkDao.getReplyLikeByUidAndCommentId(comment.getComment_id(), uid);
                if (replyLike.getLikeStatus() == 1) {
                    comment.setLikeStatus(true);
                }
            } else {
                comment.setLikeStatus(false);
            }

            User user = getUserInfoByUid(comment.getFrom_uid());
            commentForShow.setUname(user.getUname());
            commentForShow.setComment(comment);
            commentForShow.setAvatar(user.getAvatar());
            // early time show front
            commentForShowList.add(0, commentForShow);
        }
        return commentForShowList;

    }

    // todo: judge user login status for assign comment likeStatus
    public List<Comment> getTalkCommentByTalkId(int talkId) {

        return this.talkDao.getTalkCommentByTalkId(talkId);
    }

    public User getUserInfoByUid(int uid) {
        return this.talkDao.getUserByUid(uid);
    }



    @Override
    public boolean postTalkComment(String content, int talkId, int talkUid, int uId) {
        Date dateTime = new Date();
        Comment comment = new Comment();
        comment.setTalk_id(talkId);
        comment.setFrom_uid(uId);
        comment.setTo_uid(talkUid);
        comment.setContent(content);
        comment.setCreate_time(dateTime);
        // post success comment count + 1
        if (this.talkDao.updateComment(comment) == 1) {
            talkCommentAdd(talkId);
            return true;
        }
        else {
            return false;
        }

    }

    /**
     * change comment likeStatus
     * @param comment_id
     * @param u_id
     * @param likeStatus
     * @return
     */
    @Transactional
    @Override
    public Comment changeCommentLikeState(int comment_id, int u_id, boolean likeStatus) {
        Comment comment = this.talkDao.getCommentByCommentId(comment_id);
        int count = 0;
        try {
            ReplyLike replyLike = this.talkDao.getReplyLikeByUidAndCommentId(comment_id, u_id);

            if(replyLike == null) {
                // use 0/1 represent likeStats, 0 means like not, 1 means opposite
                this.talkDao.SetReplyLikeStatusOpp(comment_id, u_id, likeStatus ? 0 : 1);
                this.talkDao.CommentLikeCount(comment_id, comment.getLike_count() + 1);
                count = comment.getLike_count() + 1;
            } else {
                likeStatus = replyLike.getLikeStatus() == 1;
                this.talkDao.updateReplyLike(comment_id, u_id, likeStatus ? 0 : 1);
                this.talkDao.CommentLikeCount(comment_id, likeStatus ? comment.getLike_count() - 1 : comment.getLike_count() + 1);
                count = likeStatus ? comment.getLike_count() - 1 : comment.getLike_count() + 1;
            }
            comment.setLikeStatus(!likeStatus);
            comment.setLike_count(count);
        } catch (Exception e) {
            e.printStackTrace();
            return comment;
        }
        return comment;
    }

    private void talkCommentAdd(int talkId) {
        List<Comment> commentList = getTalkCommentByTalkId(talkId);
        int countNow = commentList.size();
        this.talkDao.talkCommentAdd(talkId, countNow);
    }
}
